package 并发编程.completionService;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 类说明：
 */
public class CompletionServiceCase {
    private final int POOL_SIZE = Runtime.getRuntime().availableProcessors();
    private final int TOTAL_TASK = Runtime.getRuntime().availableProcessors();

    // 方法一，自己写集合来实现获取线程池中任务的返回结果
    // 因 第一个for循环加入 队列是顺序的，所以第二个取线程也是顺序的，
    // 故 当第二个线程执行完毕后 要等第一个线程执行被取走了 才能 接着取第二个线程，
    // 所以 会导致CPU资源的浪费
    public void testByQueue() throws Exception {
        long start = System.currentTimeMillis();
        //统计所有任务休眠的总时长
        AtomicInteger count = new AtomicInteger(0);
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        //容器存放提交给线程池的任务,list,map,
        BlockingQueue<Future<Integer>> queue =
                new LinkedBlockingQueue<Future<Integer>>();

        // 向里面扔任务
        for (int i = 0; i < TOTAL_TASK; i++) {
            Future<Integer> future = pool.submit(new WorkTask("ExecTask" + i));
            queue.add(future);//i=0 先进队列，i=1的任务跟着进
        }

        // 检查线程池任务执行结果
        for (int i = 0; i < TOTAL_TASK; i++) {
            int sleptTime = queue.take().get();///i=0先取到，i=1的后取到
            System.out.println(" slept " + sleptTime + " ms ...");
            count.addAndGet(sleptTime);
        }

        // 关闭线程池
        pool.shutdown();
        System.out.println("-------------tasks sleep time " + count.get()
                + "ms,and spend time "
                + (System.currentTimeMillis() - start) + " ms");
    }

    // 方法二，通过CompletionService来实现获取线程池中任务的返回结果
    // 线程先完成先拿到； 实现原理：QueueingFuture 继承 FutureTask， 修改done 方法，当线程执行完毕，才加入阻塞队列
    public void testByCompletion() throws Exception {
        long start = System.currentTimeMillis();
        AtomicInteger count = new AtomicInteger(0);
        // 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        CompletionService<Integer> cService = new ExecutorCompletionService<>(pool);

        // 向里面扔任务
        for (int i = 0; i < TOTAL_TASK; i++) {
            cService.submit(new WorkTask("ExecTask" + i));
        }

        // 检查线程池任务执行结果
        for (int i = 0; i < TOTAL_TASK; i++) {
            int sleptTime = cService.take().get();
            System.out.println(" slept " + sleptTime + " ms ...");
            count.addAndGet(sleptTime);
        }

        // 关闭线程池
        pool.shutdown();
        System.out.println("-------------tasks sleep time " + count.get()
                + "ms,and spend time "
                + (System.currentTimeMillis() - start) + " ms");
    }

    public static void main(String[] args) throws Exception {
        CompletionServiceCase t = new CompletionServiceCase();
        t.testByQueue();
        t.testByCompletion();
    }
}
